package com.aaron.nettystudy.handler;


import com.aaron.nettystudy.entity.RpcResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import io.netty.util.AttributeKey;

import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @ClassName NettyClientHandler
 * @description: 读取客户端发送过来的RpcResponse消息对象，将RpcResponse消息对象保存到AttributeMap上。
 * @author: 荣燊
 * @create: 2021-05-14 22:24
 **/
// 实现入栈InboundHandlerAdapter，也是接受上一个KyroDecoder处理后的数据。
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    private static final Logger logger = LoggerFactory.getLogger(NettyClientHandler.class);

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
            RpcResponse rpcResponse = (RpcResponse) msg;
            logger.info("client receive msg: [{}]", rpcResponse.toString());
            // 声明一个AttributeKey对象，key的值标记为rpcResponse。AttributeMap存储的是RpcResponse类型。
            AttributeKey<RpcResponse> key = AttributeKey.valueOf("rpcResponse");

            // 将服务端的返回结果保存到 AttributeMap 上，AttributeMap 可以看作是一个Channel的共享数据源
            // AttributeMap的key是AttributeKey，value是Attribute
//            Attribute<RpcResponse> attr = ctx.channel().attr(key);
//            attr.set(rpcResponse);
            //我们就可以根据AttributeKey找到Attribute
            //ctx.channel()获取通道。
            ctx.channel().attr(key).set(rpcResponse);
            ctx.channel().close();
        } finally {
            /**
             * 从InBound里读取的ByteBuf要手动释放，自己创建的ByteBuf要自己负责释放。这两处要调用这个release方法。
             * write Bytebuf到OutBound时由netty负责释放，不需要手动调用release
             */
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        logger.error("client caught exception", cause);
        ctx.close();
    }
}
